class_name TankHull3D extends VehicleBody3D

signal health_changed(health_value, max_health)

const SPEED_DEAD_ZONE = 0.2

@export var health: int
@export var engine_power = 200
@export var brake_power = 10
@export var brake_power_idle = 2
@export var turn_power_multiptier = 5
@export var max_speed = 5.0

var left: Array[VehicleWheel3D]
var right: Array[VehicleWheel3D]
var wheels: Array[VehicleWheel3D]
var max_health: int

var drive_direction: TankGlobals.DriveDirection = TankGlobals.DriveDirection.P:
	set(value):
		drive_direction = get_corrected_drive_direction(value)

var DRIVE_VALUES = {
	TankGlobals.DriveDirection.P: {
		TankGlobals.DriveLabels.GAS_LEFT: 0,
		TankGlobals.DriveLabels.GAS_RIGHT: 0,
		TankGlobals.DriveLabels.BRAKE_LEFT: brake_power_idle,
		TankGlobals.DriveLabels.BRAKE_RIGHT: brake_power_idle,
	},
	TankGlobals.DriveDirection.F: {
		TankGlobals.DriveLabels.GAS_LEFT: 1,
		TankGlobals.DriveLabels.GAS_RIGHT: 1,
		TankGlobals.DriveLabels.BRAKE_LEFT: 0,
		TankGlobals.DriveLabels.BRAKE_RIGHT: 0,
	},
	TankGlobals.DriveDirection.B: {
		TankGlobals.DriveLabels.GAS_LEFT: -1,
		TankGlobals.DriveLabels.GAS_RIGHT: -1,
		TankGlobals.DriveLabels.BRAKE_LEFT: 0,
		TankGlobals.DriveLabels.BRAKE_RIGHT: 0,
	},
	TankGlobals.DriveDirection.L: {
		TankGlobals.DriveLabels.GAS_LEFT: -turn_power_multiptier,
		TankGlobals.DriveLabels.GAS_RIGHT: turn_power_multiptier,
		TankGlobals.DriveLabels.BRAKE_LEFT: 0,
		TankGlobals.DriveLabels.BRAKE_RIGHT: 0,
	},
	TankGlobals.DriveDirection.R: {
		TankGlobals.DriveLabels.GAS_LEFT: turn_power_multiptier,
		TankGlobals.DriveLabels.GAS_RIGHT: -turn_power_multiptier,
		TankGlobals.DriveLabels.BRAKE_LEFT: 0,
		TankGlobals.DriveLabels.BRAKE_RIGHT: 0,
	},
	TankGlobals.DriveDirection.FL: {
		TankGlobals.DriveLabels.GAS_LEFT: 0,
		TankGlobals.DriveLabels.GAS_RIGHT: turn_power_multiptier,
		TankGlobals.DriveLabels.BRAKE_LEFT: brake_power,
		TankGlobals.DriveLabels.BRAKE_RIGHT: 0,
	},
	TankGlobals.DriveDirection.FR: {
		TankGlobals.DriveLabels.GAS_LEFT: turn_power_multiptier,
		TankGlobals.DriveLabels.GAS_RIGHT: 0,
		TankGlobals.DriveLabels.BRAKE_LEFT: 0,
		TankGlobals.DriveLabels.BRAKE_RIGHT: brake_power,
	},
	TankGlobals.DriveDirection.BL: {
		TankGlobals.DriveLabels.GAS_LEFT: 0,
		TankGlobals.DriveLabels.GAS_RIGHT: -turn_power_multiptier,
		TankGlobals.DriveLabels.BRAKE_LEFT: brake_power,
		TankGlobals.DriveLabels.BRAKE_RIGHT: 0,
	},
	TankGlobals.DriveDirection.BR: {
		TankGlobals.DriveLabels.GAS_LEFT: -turn_power_multiptier,
		TankGlobals.DriveLabels.GAS_RIGHT: 0,
		TankGlobals.DriveLabels.BRAKE_LEFT: 0,
		TankGlobals.DriveLabels.BRAKE_RIGHT: brake_power,
	},
	TankGlobals.DriveDirection.H: {
		TankGlobals.DriveLabels.GAS_LEFT: 0,
		TankGlobals.DriveLabels.GAS_RIGHT: 0,
		TankGlobals.DriveLabels.BRAKE_LEFT: brake_power,
		TankGlobals.DriveLabels.BRAKE_RIGHT: brake_power,
	},
}

func _ready():
	max_health = health
	for child in get_children():
		if child is VehicleWheel3D:
			if child.name.begins_with('L'):
				left.append(child)
			if child.name.begins_with('R'):
				right.append(child)
			wheels = left + right

func _process(delta):
	drive(drive_direction)

func drive(direction: TankGlobals.DriveDirection):
	var coefficients = DRIVE_VALUES.get(direction)
	gas(TankGlobals.Track.LEFT, get_engine_power() * coefficients.get(TankGlobals.DriveLabels.GAS_LEFT))
	gas(TankGlobals.Track.RIGHT, get_engine_power() * coefficients.get(TankGlobals.DriveLabels.GAS_RIGHT))
	brakes(TankGlobals.Track.LEFT, coefficients.get(TankGlobals.DriveLabels.BRAKE_LEFT))
	brakes(TankGlobals.Track.RIGHT, coefficients.get(TankGlobals.DriveLabels.BRAKE_RIGHT))

func gas(track: TankGlobals.Track, power: float):
	if track == TankGlobals.Track.LEFT:
		for wheel in left:
			wheel.engine_force = power
	if track == TankGlobals.Track.RIGHT:
		for wheel in right:
			wheel.engine_force = power
	if track == TankGlobals.Track.ALL:
		for wheel in wheels:
			wheel.engine_force = power

func brakes(track: TankGlobals.Track, power: float):
	if track == TankGlobals.Track.LEFT:
		for wheel in left:
			wheel.brake = power
	if track == TankGlobals.Track.RIGHT:
		for wheel in right:
			wheel.brake = power
	if track == TankGlobals.Track.ALL:
		for wheel in wheels:
			wheel.brake = power

func get_engine_power() -> float:
	if linear_velocity.length() <= max_speed/2:
		return engine_power
	elif linear_velocity.length() <= max_speed:
		return lerp(engine_power, 0, linear_velocity.length()/max_speed)
	return 0

func get_corrected_drive_direction(raw_direction: TankGlobals.DriveDirection) -> TankGlobals.DriveDirection:
	if raw_direction == TankGlobals.DriveDirection.F:
		match get_movement_direction():
			TankGlobals.Direction.BACK:
				raw_direction = TankGlobals.DriveDirection.H
			_:
				raw_direction = TankGlobals.DriveDirection.F
	if raw_direction == TankGlobals.DriveDirection.B:
		match get_movement_direction():
			TankGlobals.Direction.FORWARD:
				raw_direction = TankGlobals.DriveDirection.H
			_:
				raw_direction = TankGlobals.DriveDirection.B
	return raw_direction

func get_movement_direction() -> TankGlobals.Direction:
	var angle = rad_to_deg(linear_velocity.angle_to(basis.z))
	var speed = linear_velocity.length()
	if speed < SPEED_DEAD_ZONE:
		return TankGlobals.Direction.HALT
	elif angle < 10 :
		return TankGlobals.Direction.FORWARD
	elif angle > 170:
		return TankGlobals.Direction.BACK
	else:
		return TankGlobals.Direction.FALL
	return TankGlobals.Direction.HALT

@rpc("any_peer")
func receive_damage(damage):
	health -= damage
	if health <= 0:
		health = max_health
		position = Vector3.ZERO
		rotation = Vector3.ZERO
		get_parent().tank_turret.rotation = Vector3(0, PI, 0)
		get_parent().tank_turret.damage = get_parent().tank_turret.default_damage
	health_changed.emit(health, max_health)

@rpc("any_peer")
func apply_force_to_body(collision_point):
	var direction = (collision_point - get_parent().global_transform.origin).normalized()
	get_parent().tank_hull.apply_impulse(Vector3(direction.x * 1000, direction.y * -500, direction.z * 1000))

